package com.caiyi.financial.nirvana.sms.shiro;

import com.caiyi.financial.nirvana.sms.entity.SmsPermission;
import com.caiyi.financial.nirvana.sms.entity.SmsRole;
import com.caiyi.financial.nirvana.sms.service.SmsPermissionService;
import com.caiyi.financial.nirvana.sms.service.SmsRoleService;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.mgt.FilterChainManager;
import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
import org.apache.shiro.web.servlet.AbstractShiroFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by Mario on 2018/1/5 0005.
 * 重写ShiroFilter
 * 添加动态更新权限方法
 */
public class SmsShiroFilterFactoryBean extends ShiroFilterFactoryBean implements ApplicationListener<ContextRefreshedEvent> {

    private Logger logger = LoggerFactory.getLogger(SmsShiroFilterFactoryBean.class);

    private SmsPermissionService permissionService;
    private SmsRoleService roleService;

    //过滤器实例
    private AbstractShiroFilter filterInstance;

    SmsShiroFilterFactoryBean(SmsPermissionService permissionService,
                              SmsRoleService roleService) {
        this.permissionService = permissionService;
        this.roleService = roleService;
    }

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        this.filterInstance = event.getApplicationContext().getBean(AbstractShiroFilter.class);
        //替换默认的roles filter,原filter不支持roles或关系授权
        this.getFilters().put("roles", new SmsAuthorizationFilter());
        this.refreshAuth();
    }

    /**
     * 刷新权限信息
     */
    public void refreshAuth() {
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        /*读取数据库role,permission配置*/
        this.initRolePermission(filterChainDefinitionMap);
        this.setFilterChainDefinitionMap(filterChainDefinitionMap);
        FilterChainManager manager = createFilterChainManager();
        PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();
        chainResolver.setFilterChainManager(manager);
        this.filterInstance.setFilterChainResolver(chainResolver);
        logger.info("已刷新权限配置");
    }

    /**
     * 加载角色权限信息到filterChainDefinitionMap
     *
     * @param filterChainDefinitionMap map
     */
    private void initRolePermission(Map<String, String> filterChainDefinitionMap) {
        /*
         * 登录接口排除限制
         */
        filterChainDefinitionMap.put("/sms/admin/login", "anon");
        filterChainDefinitionMap.put("/sms/test**/**", "anon");
        filterChainDefinitionMap.put("/druid/**", "anon");
        /*
         * 排除Swagger等静态文件
         */
        filterChainDefinitionMap.put("/swagger**/**", "anon");
        filterChainDefinitionMap.put("/webjars**/**", "anon");
        filterChainDefinitionMap.put("/v2**/**", "anon");
        /*
        验证码接口排除
         */
        filterChainDefinitionMap.put("/sms/shiro/**", "anon");
        filterChainDefinitionMap.put("/sms/admin/captcha", "anon");
        filterChainDefinitionMap.put("/sms/admin/sendCodeMessage", "anon");
        filterChainDefinitionMap.put("/sms/admin/submitMessageCode", "anon");

        List<SmsRole> smsAllRoleList = roleService.queryAll();
        List<SmsPermission> smsPermissionList = permissionService.queryAll();
        for (SmsPermission permission : smsPermissionList) {
            if (StringUtils.isBlank(permission.getUrl())) {
                continue;
            }
            List<SmsRole> smsAuthRoleList = this.fetchRolesByPermissionCode(permission.getCode(), smsAllRoleList);
            StringBuilder roles = new StringBuilder("");
            for (SmsRole item : smsAuthRoleList) {
                roles.append(item.getName());
                roles.append(",");
            }
            roles = roles.length() > 0 ? roles.deleteCharAt(roles.length() - 1) : roles;
            //添加一个默认角色，防止未配置角色的接口被访问
            filterChainDefinitionMap.put(permission.getUrl(), "authc,roles[ADMIN" + (roles.toString().equals("") ? "" : "," + roles.toString()) + "]");
        }
        /*
         * 全部接口都需要登录访问
         */
        filterChainDefinitionMap.put("/**", "authc");
    }

    /**
     * 根据权限ID，找出有访问权限的角色列表
     *
     * @param permissionCode 权限CODE
     * @param smsRoleList    全部角色
     * @return 角色列表
     */
    private List<SmsRole> fetchRolesByPermissionCode(String permissionCode, List<SmsRole> smsRoleList) {
        List<SmsRole> result = new ArrayList<>();
        for (SmsRole item : smsRoleList) {
            if (item.getPermissionCodes() != null && item.getPermissionCodes().contains(permissionCode)) {
                result.add(item);
            }
        }
        return result;
    }
}
